#ifndef TOSSABLESTRATEGY_H
#define TOSSABLESTRATEGY_H

#if defined (_WIN32)
	#pragma once
#endif

#include "../../ToolkitLayer.h"
#include <LDF/VisComponentStrategy.h>
#include <LDF/Utils/VectorTemplate.h>
#include <queue>

class Point3f;


/**
 * This strategy allows a component to be tossed. It will consider the recent
 * cursor movement to calculate the tossing direction and initial speed. As the
 * component is moving, friction will slow it down until it stops. The
 * component also stops if it reaches a region with too high friction
 * coefficient (i. e., >= 1.0).
 *
 * This strategy should be added after all the drawing strategies of a
 * component so that the decorations are drawn using the same positional
 * values.
 *
 * @author Fabricio Anastacio - fabriciocfa@yahoo.com
 * @since August 9, 2007
 */
class TOOLKITLAYER_API TossableStrategy : public VisComponentStrategy
{
	// Attributes
protected:
	/** Collection of recent cursor positions. */
	std::queue<Point3f> recentPositions;
	/** Number of cursor positions to keep track in the list. */
	unsigned int nPositions;
	/** Determines if the associated component is being tossed at the moment. */
	bool tossing;
	/** The current dynamic friction coefficient. */
	float currentFriction;
	/**
	 * Determines the standart dynamic friction coefficent to be used when tossing.
	 * It is used when the parent component does not have a friction buffer.
	 */
	float frictionCoefficient;
	/**
	 * Determines the standart static friction coefficent to be used when tossing.
	 * It determines the strenght (length) of the tossing vector necessary to
	 * start a tossing movement.
	 */
	float staticFrictionCoefficient;
	/**
	 * The minimum strength the tossing vector should have to move a component.
	 * It is compared to the value of the length of the tossing vector.
	 */
	float tossingCutoff;
	/** The vector representing the "tossing force". */
	Vector2f tossingVector;

	/** Friction buffer type identifier. */
	unsigned int frictionBufferType;


	// Methods
public:
	/**
	 * Constructs a tossable strategy.
	 */
	TossableStrategy(void);
	/**
	 * Destroys this strategy.
	 */
	~TossableStrategy(void);


	// ACCESSOR METHODS
	/**
	 * Returns true if the component is being tossed.
	 *
	 * @return true if the component is being tossed, false otherwise.
	 */
	inline bool isTossing() { return tossing; };
	/**
	 * Sets if the component is being tossed.
	 *
	 * @param value true if the component is being tossed, false otherwise.
	 */
	inline void setTossing(bool value) { tossing = value; };
	/**
	 * Returns the current dynamic friction coefficient being used when
	 * tossing.
	 *
	 * @return the current dynamic friction coefficient.
	 */
	inline float getCurrentFriction() { return currentFriction; };
	/**
	 * Sets the current dynamic friction coefficient being used when tossing.
	 *
	 * @param coeff the value to be set as the current dynamic friction
	 * coefficient.
	 */
	inline void setCurrentFriction(float coeff) { currentFriction = coeff; };
	/**
	 * Returns the default dynamic friction coefficient being used when
	 * tossing. This value is used when the parent component does not have a
	 * friction buffer.
	 *
	 * @return the default dynamic friction coefficient.
	 */
	inline float getFrictionCoefficient() { return frictionCoefficient; };
	/**
	 * Sets the default dynamic friction coefficient being used when tossing.
	 * This value is used when the parent component does not have a friction
	 * buffer.
	 *
	 * @param coeff the value to be set as the default dynamic friction
	 * coefficient.
	 */
	inline void setFrictionCoefficient(float coeff) { frictionCoefficient = coeff; };
	/**
	 * Returns the default static friction coefficient being used when tossing.
	 * This value is used when the parent component does not have a friction
	 * buffer.
	 *
	 * @return the default static friction coefficient.
	 */
	inline float getStaticFrictionCoefficient() { return staticFrictionCoefficient; };
	/**
	 * Sets the default static friction coefficient being used when tossing.
	 * This value is used when the parent component does not have a friction
	 * buffer.
	 *
	 * @param coeff the value to be set as the default static friction
	 * coefficient.
	 */
	inline void setStaticFrictionCoefficient(float coeff) { staticFrictionCoefficient = coeff; };
	/**
	 * Returns the minimum strength the tossing vector should have to move a
	 * component.
	 *
	 * @return the minimum strength the tossing vector should have to move a
	 * component.
	 */
	inline float getTossingCutoff() { return tossingCutoff; };
	/**
	 * Sets the value of the minimum strength the tossing vector should have to
	 * move a component.
	 *
	 * @param value the value to be set as the minimum strength the tossing
	 * vector should have to move a component.
	 */
	inline void setTossingCutoff(float value) { tossingCutoff = value; };


protected:
	/**
	 * Initializes the properties (i. e., i-buffers) of the associated
	 * component.
	 */
	void initProperties();
	/**
	 * Performs a given action before rendering the component.
	 */
	void process();
	/**
	 * Handles the given event.
	 *
	 * @param evt the event to be handled.
	 */
	void onEvent(LargeDisplayEvent* evt);
	/**
	 * Reads the passive buffer(s) specified by the parameter 'type' and makes
	 * the proper updates in the state of the associated component.
	 *
	 * @param type the type of buffer that should be read from the container.
	 */
	inline void readPassiveBuffers(const std::vector<unsigned int>& types);
	/**
	 * Reads all the passive buffers for a component strategy. This method is
	 * called before drawing the component in order to update its
	 * state/properties.
	 */
	inline void readAllPassiveBuffers();


private:
	/**
	 * Adds a cursor position to list discarding the oldest position.
	 */
	void addCursorPosition(unsigned int x, unsigned int y);
	// PASSIVE BUFFER READING
	/**
	 * Updates the current friction value based on the friction buffer.
	 */
	void readFriction();
};

#endif // TOSSABLESTRATEGY_H
